<template>
<div>
  <!-- 预览文章分类 -->
    <el-card class="box-card">
        <div slot="header" class="clearfix header-box">
            <span>文章分类</span>
            <el-button type="primary" size="mini" @click="addCateBtnFn">添加分类</el-button>
        </div>
        <el-table style="width: 100%" :data="cateList" border stripe>
            <el-table-column label="序号" type="index" width="100"></el-table-column>
            <el-table-column label="分类名称" prop="cate_name"></el-table-column>
            <el-table-column label="分类别名" prop="cate_alias"></el-table-column>
            <el-table-column label="操作">
              <!-- 作用域插槽:  这里的scope是一个对象,能个拿到组件暴露给slot的所有信息,包括列表的row,column等 -->
               <template v-slot="scope">
                <el-button type="primary" size="mini" @click="updateFn(scope.row)">修改</el-button>
                <el-button type="danger" size="mini" @click="deleteFn(scope.row.id)">删除</el-button>
               </template>
            </el-table-column>
        </el-table>
    </el-card>
    <!-- 添加分类的对话框 -->
    <!-- .sync作用实现双向数据绑定
      会在运行时给所在标签绑定 @update:属性名的事件, 把接收到子组件内传来的值赋予给右侧Vue变量
      组件内$emit('update:visible', true)     vue2里一个标签上v-model只能用一次,vue3可以用多次(所以vue3移除了.sync)
      这个update: 是固定的-->
      <!-- 这里使用.sync的原因:组件内监测到对话框关闭(点击蒙层,esc,按右上角x等非代码控制方式),它会z回传一个false给右侧的变量    这些其他的关闭方式是组件内置的 -->
    <el-dialog title="添加文章分类" :visible.sync="addVisible" width="35%" @closed="onAddClosedFn">
        <!-- 添加的表单 -->
        <el-form :model="addForm" :rules="addRules" ref="addRef" label-width="80px">
            <el-form-item label="分类名称" prop="cate_name">
                <el-input v-model="addForm.cate_name" minlength="1" maxlength="10"></el-input>
            </el-form-item>
            <el-form-item label="分类别名" prop="cate_alias">
                <el-input v-model="addForm.cate_alias" minlength="1" maxlength="15"></el-input>
            </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button size="mini" @click="cancelFn">取 消</el-button>
            <el-button size="mini" type="primary" @click="addFn">添 加</el-button>
        </span>
    </el-dialog>
</div>
</template>

<script>
import {
  addArticleAPI, getArticleCateAPI, updateArticleAPI, delArticleAPI
} from '@/api'
export default {
  name: 'ArticleCate',
  data () {
    return {
      // 文章的分类列表
      cateList: [],
      addVisible: false, // 添加分类-对话框是否显示
      editId: '', // 要修改的分类id
      isEdit: false, // 保存编辑状态(false新增,true编辑)
      addForm: { // 添加表单的数据对象
        cate_name: '',
        cate_alias: ''
      },
      addRules: { // 添加表单的验证规则对象
        cate_name: [{
          required: true,
          message: '请输入分类名称',
          trigger: 'blur'
        },
        {
          pattern: /^\S{1,10}$/,
          message: '分类名必须是1-10位的非空字符',
          trigger: 'blur'
        }
        ],
        cate_alias: [{
          required: true,
          message: '请输入分类别名',
          trigger: 'blur'
        },
        {
          pattern: /^[a-zA-Z0-9]{1,15}$/,
          message: '分类别名必须是1-15位的字母数字',
          trigger: 'blur'
        }
        ]
      }
    }
  },
  mounted () {
    //  获取文章分类
    this.getArticleCate()
  },
  methods: {
    // 获取文章分类
    async getArticleCate () {
      const {
        data: res
      } = await getArticleCateAPI()
      console.log(res)
      // if (res.code !== 0) return this.$message.error('获取文章分类失败')
      // this.$message.success('获取文章分类成功')  //过多提示冗余
      if (res.code === 0) {
        this.cateList = res.data
      } else {
        this.$message.error('获取文章分类失败')
      }
      //   console.log(this.cateList)
    },
    // 添加文章分类按钮点击事件
    addCateBtnFn () {
      this.isEdit = false// 修改状态为新增
      this.editId = '' // id清空
      this.addVisible = true // 对话框显示
    },
    // 添加(修改)文章分类(确定按钮)
    addFn () {
      this.$refs.addRef.validate(async valid => {
        if (valid) {
          // 这里要做判断.因为新增和修改使用的是同一个窗口和按钮,但是调用的不是同一个id
          if (!this.isEdit) {
            // 新增
            const { data: res } = await addArticleAPI(this.addForm)
            // console.log(res)
            if (res.code !== 0) return this.$message.error('添加文章分类失败')
            this.$message.success('添加文章分类成功')
            this.getArticleCate()
            this.addVisible = false // 关闭弹框放在最后面 放在校验内部即可,只有校验通过才能添加
          } else {
            // 修改
            // this.addForm.id = this.editId  // 方式一
            const { data: res } = await updateArticleAPI({ id: this.editId, ...this.addForm }) // 方式二
            // console.log(res)
            if (res.code !== 0) return this.$message.error('修改文章分类失败')
            this.$message.success('修改文章分类成功')
            this.getArticleCate()
            this.addVisible = false // 关闭弹框放在最后面 放在校验内部即可,只有校验通过才能添加
          }
        } else {
          return false
        }
      })
    },
    // 对话框内-取消按钮-点击事件
    cancelFn () {
      this.addVisible = false
    },
    // 关闭对话框时表单重置
    onAddClosedFn () {
      this.$refs.addRef.resetFields()
    },
    // 文章分类修改
    updateFn (obj) {
      this.editId = obj.id // 保存要编辑的分类id
      this.isEdit = true // 设置编辑状态
      this.addVisible = true // 让对话框显示

      // 设置数据回显
      // $nextTick的使用时为了解决,当用户先点击修改,再点击新增时,新增出现的弹框会有值的情况
      // 为什么会出现这种情况:
      // 1.Dialog的内容是懒渲染的,即在第一次被打开之前,传入的默认slot不会被渲染到DOM上
      // (简单理解:最开始时定义的空字符串不会被渲染到DOM上,只有第一次打开对话框后进行的赋值才会被当成默认值)
      // 2.Vue数据改变(先执行同步所有代码),再去更新DOM(异步代码)
      // 3.先点击修改,对话框组件挂载后会将分类的值赋给定义好的变量,此时分类的值就成了默认值,resetFields也将其当做重置值
      // 4.解决方法:让下面的数据回显慢一点执行(定时器等),即变为异步 $nextTick():等DOM更新完成之后再执行代码
      this.$nextTick(() => {
        // 先让对话框出现,它绑定空值的对象,才能resetFields清空初始化的值
        this.addForm.cate_alias = obj.cate_alias
        this.addForm.cate_name = obj.cate_name
      })
    },
    // 删除文章分类
    async deleteFn (id) {
      const { data: res } = await delArticleAPI(id)
      if (res.code !== 0) return this.$message.error('删除分类失败！')
      this.$message.success('删除分类成功！')
      this.getArticleCate() // 刷新列表
    }

  }
}
</script>

<!--
  v-model的本质:
    在标签上使用  v-model='val'   ===> (解析为v-bind和v-on的联合使用)
    实际解析是:  v-bind:value='val'  @/v-on:input='val = $event.target.value' 或 @/v-on:input='val => val = $event.target.value'(箭头函数)

  拓展:(.sync实现双向数据绑定,目的:vue2中一个标签上也能出现多个双向数据绑定)
  .sync本质:
  给所在标签绑定  :/v-bind:props属性名 = 'Vue变量' @/v-on:update:props属性名 = 'val => Vue变量 = val'
    例如: <标签 visible.sync = 'addVisible'><标签/>
    运行时: <标签 :visible = 'addVisible' @update:visible = 'val => addVisible = val'><标签/>
            子组件内子传父时: this.$emit("update:visible",值)   update是固定的,后面的属性名根据绑定时定义的改
 -->

 <!--
  经验:如果想用同一个按钮做状态区分
  1.定义一个变量isEdit,还要定义一个本次要编辑的数据唯一的id值,editId
  2.在点击修改的时候,isEdit修改为true,editId保存要修改的数据id值
  3.在点击新增按钮的时候,isEdit的值改为false,editId清空
  4.在点击保存时,就可以用isEdit变量区分

  -->
<style lang="less" scoped>
.header-box {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
</style>
